﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.ServiceModel;
using System.Text;
using Contracts;
using Events;

namespace Model
{
    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
    public class Model : Contracts.IClient
    {
        #region Models events - occurs when a user status change, when a message is received etc.
        // application messages handlers
        public delegate void AppMessageHandler(object sender, AppMessageEventArgs e);
        public event AppMessageHandler OnAppMessageReceived;

        // user messages handlers
        public delegate void UserMessageHandler(object sender, UserMessageEventArgs e);
        public event UserMessageHandler OnUserMessageReceived;

        // contact changed handlers
        public delegate void ContactChangedHandler(object sender, ContactEventArgs e);
        public event ContactChangedHandler OnContactChange;
        #endregion

        #region channel factory and channel
        private DuplexChannelFactory<Contracts.IServer> channelFactory;
        private Contracts.IServer channel;
        #endregion

        private List<Contact> contactList = new List<Contact>();

        protected void createChannel()
        {
            this.channelFactory = new DuplexChannelFactory<Contracts.IServer>(this, "configClient");
            this.channel = channelFactory.CreateChannel();
        }

        public bool Login(string mail, string password)
        {
            this.createChannel();
            try
            {
                channel.Login(mail, password);
            }
            // The server closed the connection because the login failed
            catch (CommunicationException)
            {
                return false;
            }
            
            return true;
        }

        public void Logout()
        {
            this.channel.Logout();
        }

        public User GetUser()
        {
            return this.channel.GetUser();
        }

        public bool AddUser(string mail, string password)
        {
            this.createChannel();
            return this.channel.AddUser(mail, password);
        }

        public void UpdateUser(User theUser)
        {
            this.channel.UpdateUser(theUser);
        }

        public List<Contact> GetContacts()
        {
            this.contactList = this.channel.GetContactList();
            return contactList;
        }

        public void SendMessage(string to, string message)
        {
            this.channel.SendMessage(to, message);
        }

        public List<Message> GetUnreadMessages()
        {
             return this.channel.GetUnreadMessages();
        }

        public bool AddContact(Contact theContact)
        {
            return this.channel.AddContact(theContact);
        }

        public bool DeleteContact(string mail)
        {
            return this.channel.DeleteContact(mail);
        }

        public bool EditContact(Contact theContact)
        {
            return this.channel.EditContact(theContact);
        }

        public List<string> GetGroupList()
        {
            return this.channel.GetGroupList();
        }

        public Image GetAvatar(string mail)
        {
            try
            {
                byte[] byteImage = this.channel.DownloadAvatar(mail);
                MemoryStream ms = new MemoryStream(byteImage);
                return Image.FromStream(ms);
            }
            catch (ArgumentNullException)
            {
                return Image.FromFile("..\\..\\avatar.jpg");
            }

        }

        public void SetAvatar(Image image)
        {
            MemoryStream ms = new MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            this.channel.UploadAvatar(ms.ToArray());
        }

        public void ReceptError(string error)
        {
            // when an application message is received, launch an event.
            OnAppMessageReceived(this, new AppMessageEventArgs(error));
        }

        public void ReceptMessage(Message message)
        {
            // when an user message is received, launch an event
            OnUserMessageReceived(this, new UserMessageEventArgs(message));
        }

        public void ReceptContactChange(Contact newContact)
        {
            Contact contact = (from c in this.contactList
                               where c.Mail.Equals(newContact.Mail)
                               select c).FirstOrDefault();

            // I've received a notification for an user I have not in my contact list ? Just ignore this.
            if(contact == null)
                return;

            // create an event
            OnContactChange(this, new ContactEventArgs(newContact));
        }

        public string getSha1String(string inputString)
        {
            return BitConverter.ToString(SHA1Managed.Create().ComputeHash(Encoding.Default.GetBytes(inputString))).Replace("-", "").ToLower();
        }
    }

}
